﻿using CommonLib.CacheOperation;
using CommonLib.LogOperation;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using WCFLib.Client;

namespace WCFLib.Behaviour
{
    /// <summary>
    /// 被拦截的操作行为
    /// </summary>
    public class InterceptedOperationBehaviour : IOperationBehavior, IParameterInspector
    {
        private static readonly string m_printParameterInterceptHeadKey = "PrintParameterInterceptHead";
        private string m_printParameterInterceptHead = "";

        private static readonly string m_printParameterKey = "PrintParameter";
        private bool m_isPrintParameter = false;

        private static readonly string m_printCallKey = "PrintCall";
        private bool m_isPrintCall = false;

        public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {

        }

        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {

        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            dispatchOperation.ParameterInspectors.Add(this);

            PrintParameter(dispatchOperation);
        }

        private void PrintParameter(DispatchOperation dispatchOperation)
        {
            m_printParameterInterceptHead = AppConfigCache.GetAppSettings(m_printParameterInterceptHeadKey);

            bool.TryParse(AppConfigCache.GetAppSettings(m_printParameterKey), out m_isPrintParameter);
            bool.TryParse(AppConfigCache.GetAppSettings(m_printCallKey), out m_isPrintCall);

            if (m_isPrintParameter)
            {
                Logger.Warning(dispatchOperation.Name + "打印参数功能已经开启");
            }
        }

        public void Validate(OperationDescription operationDescription)
        {

        }

        public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
        {
            if (!m_isPrintCall) return;

            Logger.Info(string.Format("[终端地址-{0}],[After标识-{1}],[操作-{2}]", ClientHelper.GetIPAndPort(), correlationState.ToString(), operationName));
        }

        public object BeforeCall(string operationName, object[] inputs)
        {
            if (!m_isPrintCall)
            {
                return null;
            }

            Guid guid = Guid.NewGuid();

            Logger.Info(string.Format("[终端地址-{0}],[Before标识-{1}],[操作-{2}]", ClientHelper.GetIPAndPort(), guid.ToString(), operationName));

            PrintParameter(inputs);

            return guid;
        }

        private void PrintParameter(object[] inputs)
        {
            if (!m_isPrintParameter)
            {
                return;
            }

            if (inputs == null || inputs.Length == 0)
            {
                return;
            }

            Type type = null;

            foreach (var input in inputs)
            {
                if (input == null)
                {
                    Logger.Info("inputs is null");
                    continue;
                }

                type = input.GetType();

                Logger.Info("Type:" + type.Name);

                if (type.IsGenericType)
                {
                    Logger.Info("Generic.Count = " + ((dynamic)input).Count);
                }
                else if (IsPrimitiveType(type))
                {
                    Logger.Info(string.Format("{0} = {1}", type.Name, input));
                    continue;
                }

                if (!string.IsNullOrWhiteSpace(m_printParameterInterceptHead) && !input.GetType().FullName.StartsWith(m_printParameterInterceptHead))
                {
                    continue;
                }

                var properties = type.GetProperties();

                foreach (var property in properties)
                {
                    Logger.Info(string.Format("{0} = {1}", property.Name, property.GetValue(input, null)));
                }
            }
        }

        private bool IsPrimitiveType(Type type)
        {
            switch (type.Name.ToLower())
            {
                case "string":
                case "int16":
                case "int32":
                case "int64":
                case "float":
                case "double":
                case "decimal":
                    return true;
                default:
                    return false;
            }
        }
    }
}
